(function (exports, ByteArray, global) {
    var Protocol = exports;
    var PKG_HEAD_BYTES = 4;
    var MSG_FLAG_BYTES = 1;
    var MSG_ROUTE_CODE_BYTES = 2;
    var MSG_ID_MAX_BYTES = 5;
    var MSG_ROUTE_LEN_BYTES = 1;
    var MSG_ROUTE_CODE_MAX = 0xffff;
    var MSG_COMPRESS_ROUTE_MASK = 0x1;
    var MSG_TYPE_MASK = 0x7;
    var Package = Protocol.Package = {};
    var Message = Protocol.Message = {};
    Package.TYPE_HANDSHAKE = 1;
    Package.TYPE_HANDSHAKE_ACK = 2;
    Package.TYPE_HEARTBEAT = 3;
    Package.TYPE_DATA = 4;
    Package.TYPE_KICK = 5;
    Message.TYPE_REQUEST = 0;
    Message.TYPE_NOTIFY = 1;
    Message.TYPE_RESPONSE = 2;
    Message.TYPE_PUSH = 3;
    /**
     * pomele client encode
     * id message id;
     * route message route
     * msg message body
     * socketio current support string
     */
    Protocol.strencode = function (str) {
        var byteArray = new ByteArray(str.length * 3);
        var offset = 0;
        for (var i = 0; i < str.length; i++) {
            var charCode = str.charCodeAt(i);
            var codes = null;
            if (charCode <= 0x7f) {
                codes = [charCode];
            }
            else if (charCode <= 0x7ff) {
                codes = [0xc0 | (charCode >> 6), 0x80 | (charCode & 0x3f)];
            }
            else {
                codes = [0xe0 | (charCode >> 12), 0x80 | ((charCode & 0xfc0) >> 6), 0x80 | (charCode & 0x3f)];
            }
            for (var j = 0; j < codes.length; j++) {
                byteArray[offset] = codes[j];
                ++offset;
            }
        }
        var _buffer = new ByteArray(offset);
        copyArray(_buffer, 0, byteArray, 0, offset);
        return _buffer;
    };
    /**
     * client decode
     * msg String data
     * return Message Object
     */
    Protocol.strdecode = function (buffer) {
        var bytes = new ByteArray(buffer);
        var array = [];
        var offset = 0;
        var charCode = 0;
        var end = bytes.length;
        while (offset < end) {
            if (bytes[offset] < 128) {
                charCode = bytes[offset];
                offset += 1;
            }
            else if (bytes[offset] < 224) {
                charCode = ((bytes[offset] & 0x3f) << 6) + (bytes[offset + 1] & 0x3f);
                offset += 2;
            }
            else {
                charCode = ((bytes[offset] & 0x0f) << 12) + ((bytes[offset + 1] & 0x3f) << 6) + (bytes[offset + 2] & 0x3f);
                offset += 3;
            }
            array.push(charCode);
        }
        return String.fromCharCode.apply(null, array);
    };
    /**
     * Package protocol encode.
     *
     * Pomelo package format:
     * +------+-------------+------------------+
     * | type | body length |       body       |
     * +------+-------------+------------------+
     *
     * Head: 4bytes
     *   0: package type,
     *      1 - handshake,
     *      2 - handshake ack,
     *      3 - heartbeat,
     *      4 - data
     *      5 - kick
     *   1 - 3: big-endian body length
     * Body: body length bytes
     *
     * @param  {Number}    type   package type
     * @param  {ByteArray} body   body content in bytes
     * @return {ByteArray}        new byte array that contains encode result
     */
    Package.encode = function (type, body) {
        var length = body ? body.length : 0;
        var buffer = new ByteArray(PKG_HEAD_BYTES + length);
        var index = 0;
        buffer[index++] = type & 0xff;
        buffer[index++] = (length >> 16) & 0xff;
        buffer[index++] = (length >> 8) & 0xff;
        buffer[index++] = length & 0xff;
        if (body) {
            copyArray(buffer, index, body, 0, length);
        }
        return buffer;
    };
    /**
     * Package protocol decode.
     * See encode for package format.
     *
     * @param  {ByteArray} buffer byte array containing package content
     * @return {Object}           {type: package type, buffer: body byte array}
     */
    Package.decode = function (buffer) {
        var offset = 0;
        var bytes = new ByteArray(buffer);
        var length = 0;
        var rs = [];
        while (offset < bytes.length) {
            var type = bytes[offset++];
            length = ((bytes[offset++]) << 16 | (bytes[offset++]) << 8 | bytes[offset++]) >>> 0;
            var body = length ? new ByteArray(length) : null;
            copyArray(body, 0, bytes, offset, length);
            offset += length;
            rs.push({ 'type': type, 'body': body });
        }
        return rs.length === 1 ? rs[0] : rs;
    };
    /**
     * Message protocol encode.
     *
     * @param  {Number} id            message id
     * @param  {Number} type          message type
     * @param  {Number} compressRoute whether compress route
     * @param  {Number|String} route  route code or route string
     * @param  {Buffer} msg           message body bytes
     * @return {Buffer}               encode result
     */
    Message.encode = function (id, type, compressRoute, route, msg) {
        // caculate message max length
        var idBytes = msgHasId(type) ? caculateMsgIdBytes(id) : 0;
        var msgLen = MSG_FLAG_BYTES + idBytes;
        if (msgHasRoute(type)) {
            if (compressRoute) {
                if (typeof route !== 'number') {
                    throw new Error('error flag for number route!');
                }
                msgLen += MSG_ROUTE_CODE_BYTES;
            }
            else {
                msgLen += MSG_ROUTE_LEN_BYTES;
                if (route) {
                    route = Protocol.strencode(route);
                    if (route.length > 255) {
                        throw new Error('route maxlength is overflow');
                    }
                    msgLen += route.length;
                }
            }
        }
        if (msg) {
            msgLen += msg.length;
        }
        var buffer = new ByteArray(msgLen);
        var offset = 0;
        // add flag
        offset = encodeMsgFlag(type, compressRoute, buffer, offset);
        // add message id
        if (msgHasId(type)) {
            offset = encodeMsgId(id, buffer, offset);
        }
        // add route
        if (msgHasRoute(type)) {
            offset = encodeMsgRoute(compressRoute, route, buffer, offset);
        }
        // add body
        if (msg) {
            offset = encodeMsgBody(msg, buffer, offset);
        }
        return buffer;
    };
    /**
     * Message protocol decode.
     *
     * @param  {Buffer|Uint8Array} buffer message bytes
     * @return {Object}            message object
     */
    Message.decode = function (buffer) {
        var bytes = new ByteArray(buffer);
        var bytesLen = bytes.length || bytes.byteLength;
        var offset = 0;
        var id = 0;
        var route = null;
        // parse flag
        var flag = bytes[offset++];
        var compressRoute = flag & MSG_COMPRESS_ROUTE_MASK;
        var type = (flag >> 1) & MSG_TYPE_MASK;
        // parse id
        if (msgHasId(type)) {
            var m = parseInt(bytes[offset]);
            var i = 0;
            do {
                var m = parseInt(bytes[offset]);
                id = id + ((m & 0x7f) * Math.pow(2, (7 * i)));
                offset++;
                i++;
            } while (m >= 128);
        }
        // parse route
        if (msgHasRoute(type)) {
            if (compressRoute) {
                route = (bytes[offset++]) << 8 | bytes[offset++];
            }
            else {
                var routeLen = bytes[offset++];
                if (routeLen) {
                    route = new ByteArray(routeLen);
                    copyArray(route, 0, bytes, offset, routeLen);
                    route = Protocol.strdecode(route);
                }
                else {
                    route = '';
                }
                offset += routeLen;
            }
        }
        // parse body
        var bodyLen = bytesLen - offset;
        var body = new ByteArray(bodyLen);
        copyArray(body, 0, bytes, offset, bodyLen);
        return {
            'id': id, 'type': type, 'compressRoute': compressRoute,
            'route': route, 'body': body
        };
    };
    var copyArray = function (dest, doffset, src, soffset, length) {
        if ('function' === typeof src.copy) {
            // Buffer
            src.copy(dest, doffset, soffset, soffset + length);
        }
        else {
            // Uint8Array
            for (var index = 0; index < length; index++) {
                dest[doffset++] = src[soffset++];
            }
        }
    };
    var msgHasId = function (type) {
        return type === Message.TYPE_REQUEST || type === Message.TYPE_RESPONSE;
    };
    var msgHasRoute = function (type) {
        return type === Message.TYPE_REQUEST || type === Message.TYPE_NOTIFY ||
            type === Message.TYPE_PUSH;
    };
    var caculateMsgIdBytes = function (id) {
        var len = 0;
        do {
            len += 1;
            id >>= 7;
        } while (id > 0);
        return len;
    };
    var encodeMsgFlag = function (type, compressRoute, buffer, offset) {
        if (type !== Message.TYPE_REQUEST && type !== Message.TYPE_NOTIFY &&
            type !== Message.TYPE_RESPONSE && type !== Message.TYPE_PUSH) {
            throw new Error('unkonw message type: ' + type);
        }
        buffer[offset] = (type << 1) | (compressRoute ? 1 : 0);
        return offset + MSG_FLAG_BYTES;
    };
    var encodeMsgId = function (id, buffer, offset) {
        do {
            var tmp = id % 128;
            var next = Math.floor(id / 128);
            if (next !== 0) {
                tmp = tmp + 128;
            }
            buffer[offset++] = tmp;
            id = next;
        } while (id !== 0);
        return offset;
    };
    var encodeMsgRoute = function (compressRoute, route, buffer, offset) {
        if (compressRoute) {
            if (route > MSG_ROUTE_CODE_MAX) {
                throw new Error('route number is overflow');
            }
            buffer[offset++] = (route >> 8) & 0xff;
            buffer[offset++] = route & 0xff;
        }
        else {
            if (route) {
                buffer[offset++] = route.length & 0xff;
                copyArray(buffer, offset, route, 0, route.length);
                offset += route.length;
            }
            else {
                buffer[offset++] = 0;
            }
        }
        return offset;
    };
    var encodeMsgBody = function (msg, buffer, offset) {
        copyArray(buffer, offset, msg, 0, msg.length);
        return offset + msg.length;
    };
    if (typeof (window) != "undefined") {
        window.Protocol = Protocol;
    }
})(typeof (window) == "undefined" ? module.exports : (window.Protocol = {}), typeof (window) == "undefined" ? Buffer : Uint8Array, window);
(function () {
    function Emitter(obj) {
        if (obj)
            return mixin(obj);
    }
    /**
   * Mixin the emitter properties.
   *
   * @param {Object} obj
   * @return {Object}
   * @api private
   */
    function mixin(obj) {
        for (var key in Emitter.prototype) {
            obj[key] = Emitter.prototype[key];
        }
        return obj;
    }
    /**
     * Listen on the given `event` with `fn`.
     *
     * @param {String} event
     * @param {Function} fn
     * @return {Emitter}
     * @api public
     */
    Emitter.prototype.on =
        Emitter.prototype.addEventListener = function (event, fn) {
            this._callbacks = this._callbacks || {};
            (this._callbacks[event] = this._callbacks[event] || [])
                .push(fn);
            return this;
        };
    /**
     * Adds an `event` listener that will be invoked a single
     * time then automatically removed.
     *
     * @param {String} event
     * @param {Function} fn
     * @return {Emitter}
     * @api public
     */
    Emitter.prototype.once = function (event, fn) {
        var self = this;
        this._callbacks = this._callbacks || {};
        function on() {
            self.off(event, on);
            fn.apply(this, arguments);
        }
        on.fn = fn;
        this.on(event, on);
        return this;
    };
    /**
     * Remove the given callback for `event` or all
     * registered callbacks.
     *
     * @param {String} event
     * @param {Function} fn
     * @return {Emitter}
     * @api public
     */
    Emitter.prototype.off =
        Emitter.prototype.removeListener =
            Emitter.prototype.removeAllListeners =
                Emitter.prototype.removeEventListener = function (event, fn) {
                    this._callbacks = this._callbacks || {};
                    // all
                    if (0 == arguments.length) {
                        this._callbacks = {};
                        return this;
                    }
                    // specific event
                    var callbacks = this._callbacks[event];
                    if (!callbacks)
                        return this;
                    // remove all handlers
                    if (1 == arguments.length) {
                        delete this._callbacks[event];
                        return this;
                    }
                    // remove specific handler
                    var cb;
                    for (var i = 0; i < callbacks.length; i++) {
                        cb = callbacks[i];
                        if (cb === fn || cb.fn === fn) {
                            callbacks.splice(i, 1);
                            break;
                        }
                    }
                    return this;
                };
    /**
     * Emit `event` with the given args.
     *
     * @param {String} event
     * @param {Mixed} ...
     * @return {Emitter}
     */
    Emitter.prototype.emit = function (event) {
        this._callbacks = this._callbacks || {};
        var args = [].slice.call(arguments, 1), callbacks = this._callbacks[event];
        if (callbacks) {
            callbacks = callbacks.slice(0);
            for (var i = 0, len = callbacks.length; i < len; ++i) {
                callbacks[i].apply(this, args);
            }
        }
        return this;
    };
    /**
     * Return array of callbacks for `event`.
     *
     * @param {String} event
     * @return {Array}
     * @api public
     */
    Emitter.prototype.listeners = function (event) {
        this._callbacks = this._callbacks || {};
        return this._callbacks[event] || [];
    };
    /**
     * Check if this emitter has `event` handlers.
     *
     * @param {String} event
     * @return {Boolean}
     * @api public
     */
    Emitter.prototype.hasListeners = function (event) {
        return !!this.listeners(event).length;
    };
    var JS_WS_CLIENT_TYPE = 'js-websocket';
    var JS_WS_CLIENT_VERSION = '0.0.1';
    var Protocol = window.Protocol;
    var decodeIO_encoder = null;
    var decodeIO_decoder = null;
    var Package = Protocol.Package;
    var Message = Protocol.Message;
    var EventEmitter = Emitter;
    var rsa = window.rsa;
    var RES_OK = 200;
    var RES_FAIL = 500;
    var RES_OLD_CLIENT = 501;
    if (typeof Object.create !== 'function') {
        Object.create = function (o) {
            function F() { }
            F.prototype = o;
            return new F();
        };
    }
    var root = window;
    var nano = Object.create(EventEmitter.prototype); // object extend from object
    root.nano = nano;
    var socket = null;
    var reqId = 0;
    var callbacks = {};
    var handlers = {};
    //Map from request id to route
    var routeMap = {};
    var dict = {}; // route string to code
    var abbrs = {}; // code to route string
    var heartbeatInterval = 0;
    var heartbeatTimeout = 0;
    var nextHeartbeatTimeout = 0;
    var gapThreshold = 100; // heartbeat gap threashold
    var heartbeatId = null;
    var heartbeatTimeoutId = null;
    var handshakeCallback = null;
    var decode = null;
    var encode = null;
    var reconnect = false;
    var reconncetTimer = null;
    var reconnectUrl = null;
    var reconnectAttempts = 0;
    var reconnectionDelay = 5000;
    var DEFAULT_MAX_RECONNECT_ATTEMPTS = 10;
    var useCrypto;
    var handshakeBuffer = {
        'sys': {
            type: JS_WS_CLIENT_TYPE,
            version: JS_WS_CLIENT_VERSION,
            rsa: {}
        },
        'user': {}
    };
    var initCallback = null;
    nano.init = function (params, cb) {
        initCallback = cb;
        var host = params.host;
        var port = params.port;
        var path = params.path;
        encode = params.encode || defaultEncode;
        decode = params.decode || defaultDecode;
        var url = 'ws://' + host;
        if (port) {
            url += ':' + port;
        }
        if (path) {
            url += path;
        }
        handshakeBuffer.user = params.user;
        if (params.encrypt) {
            useCrypto = true;
            rsa.generate(1024, "10001");
            var data = {
                rsa_n: rsa.n.toString(16),
                rsa_e: rsa.e
            };
            handshakeBuffer.sys.rsa = data;
        }
        handshakeCallback = params.handshakeCallback;
        connect(params, url, cb);
    };
    var defaultDecode = nano.decode = function (data) {
        var msg = Message.decode(data);
        if (msg.id > 0) {
            msg.route = routeMap[msg.id];
            delete routeMap[msg.id];
            if (!msg.route) {
                return;
            }
        }
        msg.body = deCompose(msg);
        return msg;
    };
    var defaultEncode = nano.encode = function (reqId, route, msg) {
        var type = reqId ? Message.TYPE_REQUEST : Message.TYPE_NOTIFY;
        if (decodeIO_encoder && decodeIO_encoder.lookup(route)) {
            var Builder = decodeIO_encoder.build(route);
            msg = new Builder(msg).encodeNB();
        }
        else {
            msg = Protocol.strencode(JSON.stringify(msg));
        }
        var compressRoute = 0;
        if (dict && dict[route]) {
            route = dict[route];
            compressRoute = 1;
        }
        return Message.encode(reqId, type, compressRoute, route, msg);
    };
    var connect = function (params, url, cb) {
        console.log('connect to ' + url);
        var params = params || {};
        var maxReconnectAttempts = params.maxReconnectAttempts || DEFAULT_MAX_RECONNECT_ATTEMPTS;
        reconnectUrl = url;
        var onopen = function (event) {
            if (!!reconnect) {
                nano.emit('reconnect');
            }
            reset();
            var obj = Package.encode(Package.TYPE_HANDSHAKE, Protocol.strencode(JSON.stringify(handshakeBuffer)));
            send(obj);
        };
        var onmessage = function (event) {
            processPackage(Package.decode(event.data), cb);
            // new package arrived, update the heartbeat timeout
            if (heartbeatTimeout) {
                nextHeartbeatTimeout = Date.now() + heartbeatTimeout;
            }
        };
        var onerror = function (event) {
            nano.emit('io-error', event);
            console.error('socket error: ', event);
        };
        var onclose = function (event) {
            nano.emit('close', event);
            nano.emit('disconnect', event);
            console.log('socket close: ', event);
            if (!!params.reconnect && reconnectAttempts < maxReconnectAttempts) {
                reconnect = true;
                reconnectAttempts++;
                reconncetTimer = setTimeout(function () {
                    connect(params, reconnectUrl, cb);
                }, reconnectionDelay);
                reconnectionDelay *= 2;
            }
        };
        socket = new WebSocket(url);
        socket.binaryType = 'arraybuffer';
        socket.onopen = onopen;
        socket.onmessage = onmessage;
        socket.onerror = onerror;
        socket.onclose = onclose;
    };
    nano.disconnect = function () {
        if (socket) {
            if (socket.disconnect)
                socket.disconnect();
            if (socket.close)
                socket.close();
            console.log('disconnect');
            socket = null;
        }
        if (heartbeatId) {
            clearTimeout(heartbeatId);
            heartbeatId = null;
        }
        if (heartbeatTimeoutId) {
            clearTimeout(heartbeatTimeoutId);
            heartbeatTimeoutId = null;
        }
    };
    var reset = function () {
        reconnect = false;
        reconnectionDelay = 1000 * 5;
        reconnectAttempts = 0;
        clearTimeout(reconncetTimer);
    };
    nano.request = function (route, msg, cb) {
        if (arguments.length === 2 && typeof msg === 'function') {
            cb = msg;
            msg = {};
        }
        else {
            msg = msg || {};
        }
        route = route || msg.route;
        if (!route) {
            return;
        }
        reqId++;
        sendMessage(reqId, route, msg);
        callbacks[reqId] = cb;
        routeMap[reqId] = route;
    };
    nano.notify = function (route, msg) {
        msg = msg || {};
        sendMessage(0, route, msg);
    };
    var sendMessage = function (reqId, route, msg) {
        if (useCrypto) {
            msg = JSON.stringify(msg);
            var sig = rsa.signString(msg, "sha256");
            msg = JSON.parse(msg);
            msg['__crypto__'] = sig;
        }
        if (encode) {
            msg = encode(reqId, route, msg);
        }
        var packet = Package.encode(Package.TYPE_DATA, msg);
        send(packet);
    };
    var send = function (packet) {
        socket.send(packet.buffer);
    };
    var handler = {};
    var heartbeat = function (data) {
        if (!heartbeatInterval) {
            // no heartbeat
            return;
        }
        var obj = Package.encode(Package.TYPE_HEARTBEAT);
        if (heartbeatTimeoutId) {
            clearTimeout(heartbeatTimeoutId);
            heartbeatTimeoutId = null;
        }
        if (heartbeatId) {
            // already in a heartbeat interval
            return;
        }
        heartbeatId = setTimeout(function () {
            heartbeatId = null;
            send(obj);
            nextHeartbeatTimeout = Date.now() + heartbeatTimeout;
            heartbeatTimeoutId = setTimeout(heartbeatTimeoutCb, heartbeatTimeout);
        }, heartbeatInterval);
    };
    var heartbeatTimeoutCb = function () {
        var gap = nextHeartbeatTimeout - Date.now();
        if (gap > gapThreshold) {
            heartbeatTimeoutId = setTimeout(heartbeatTimeoutCb, gap);
        }
        else {
            console.error('server heartbeat timeout');
            nano.emit('heartbeat timeout');
            nano.disconnect();
        }
    };
    var handshake = function (data) {
        data = JSON.parse(Protocol.strdecode(data));
        if (data.code === RES_OLD_CLIENT) {
            nano.emit('error', 'client version not fullfill');
            return;
        }
        if (data.code !== RES_OK) {
            nano.emit('error', 'handshake fail');
            return;
        }
        handshakeInit(data);
        var obj = Package.encode(Package.TYPE_HANDSHAKE_ACK);
        send(obj);
        if (initCallback) {
            initCallback(socket);
        }
    };
    var onData = function (data) {
        var msg = data;
        if (decode) {
            msg = decode(msg);
        }
        processMessage(nano, msg);
    };
    var onKick = function (data) {
        data = JSON.parse(Protocol.strdecode(data));
        nano.emit('onKick', data);
    };
    handlers[Package.TYPE_HANDSHAKE] = handshake;
    handlers[Package.TYPE_HEARTBEAT] = heartbeat;
    handlers[Package.TYPE_DATA] = onData;
    handlers[Package.TYPE_KICK] = onKick;
    var processPackage = function (msgs) {
        if (Array.isArray(msgs)) {
            for (var i = 0; i < msgs.length; i++) {
                var msg = msgs[i];
                handlers[msg.type](msg.body);
            }
        }
        else {
            handlers[msgs.type](msgs.body);
        }
    };
    var processMessage = function (nano, msg) {
        if (!msg.id) {
            // server push message
            nano.emit(msg.route, msg.body);
            return;
        }
        //if have a id then find the callback function with the request
        var cb = callbacks[msg.id];
        delete callbacks[msg.id];
        if (typeof cb !== 'function') {
            return;
        }
        cb(msg.body);
    };
    var processMessageBatch = function (nano, msgs) {
        for (var i = 0, l = msgs.length; i < l; i++) {
            processMessage(nano, msgs[i]);
        }
    };
    var deCompose = function (msg) {
        var route = msg.route;
        //Decompose route from dict
        if (msg.compressRoute) {
            if (!abbrs[route]) {
                return {};
            }
            route = msg.route = abbrs[route];
        }
        if (decodeIO_decoder && decodeIO_decoder.lookup(route)) {
            return decodeIO_decoder.build(route).decode(msg.body);
        }
        else {
            return JSON.parse(Protocol.strdecode(msg.body));
        }
        return msg;
    };
    var handshakeInit = function (data) {
        if (data.sys && data.sys.heartbeat) {
            heartbeatInterval = data.sys.heartbeat * 1000; // heartbeat interval
            heartbeatTimeout = heartbeatInterval * 2; // max heartbeat timeout
        }
        else {
            heartbeatInterval = 0;
            heartbeatTimeout = 0;
        }
        initData(data);
        if (typeof handshakeCallback === 'function') {
            handshakeCallback(data.user);
        }
    };
    //Initilize data used in nano client
    var initData = function (data) {
        if (!data || !data.sys) {
            return;
        }
        dict = data.sys.dict;
        //Init compress dict
        if (dict) {
            dict = dict;
            abbrs = {};
            for (var route in dict) {
                abbrs[dict[route]] = route;
            }
        }
        window.nano = nano;
    };
})();
(function (e, h, r) { var p = e; var a = 4; var f = 1; var l = 2; var n = 5; var u = 1; var o = 65535; var y = 1; var E = 7; var t = p.Package = {}; var i = p.Message = {}; t.TYPE_HANDSHAKE = 1; t.TYPE_HANDSHAKE_ACK = 2; t.TYPE_HEARTBEAT = 3; t.TYPE_DATA = 4; t.TYPE_KICK = 5; i.TYPE_REQUEST = 0; i.TYPE_NOTIFY = 1; i.TYPE_RESPONSE = 2; i.TYPE_PUSH = 3; p.strencode = function (e) { var r = new h(e.length * 3); var n = 0; for (var t = 0; t < e.length; t++) {
    var o = e.charCodeAt(t);
    var a = null;
    if (o <= 127) {
        a = [o];
    }
    else if (o <= 2047) {
        a = [192 | o >> 6, 128 | o & 63];
    }
    else {
        a = [224 | o >> 12, 128 | (o & 4032) >> 6, 128 | o & 63];
    }
    for (var i = 0; i < a.length; i++) {
        r[n] = a[i];
        ++n;
    }
} var c = new h(n); T(c, 0, r, 0, n); return c; }; p.strdecode = function (e) { var r = new h(e); var n = []; var t = 0; var o = 0; var a = r.length; while (t < a) {
    if (r[t] < 128) {
        o = r[t];
        t += 1;
    }
    else if (r[t] < 224) {
        o = ((r[t] & 63) << 6) + (r[t + 1] & 63);
        t += 2;
    }
    else {
        o = ((r[t] & 15) << 12) + ((r[t + 1] & 63) << 6) + (r[t + 2] & 63);
        t += 3;
    }
    n.push(o);
} return String.fromCharCode.apply(null, n); }; t.encode = function (e, r) { var n = r ? r.length : 0; var t = new h(a + n); var o = 0; t[o++] = e & 255; t[o++] = n >> 16 & 255; t[o++] = n >> 8 & 255; t[o++] = n & 255; if (r) {
    T(t, o, r, 0, n);
} return t; }; t.decode = function (e) { var r = 0; var n = new h(e); var t = 0; var o = []; while (r < n.length) {
    var a = n[r++];
    t = (n[r++] << 16 | n[r++] << 8 | n[r++]) >>> 0;
    var i = t ? new h(t) : null;
    T(i, 0, n, r, t);
    r += t;
    o.push({ type: a, body: i });
} return o.length === 1 ? o[0] : o; }; i.encode = function (e, r, n, t, o) { var a = _(r) ? v(e) : 0; var i = f + a; if (w(r)) {
    if (n) {
        if (typeof t !== "number") {
            throw new Error("error flag for number route!");
        }
        i += l;
    }
    else {
        i += u;
        if (t) {
            t = p.strencode(t);
            if (t.length > 255) {
                throw new Error("route maxlength is overflow");
            }
            i += t.length;
        }
    }
} if (o) {
    i += o.length;
} var c = new h(i); var s = 0; s = d(r, n, c, s); if (_(r)) {
    s = b(e, c, s);
} if (w(r)) {
    s = g(n, t, c, s);
} if (o) {
    s = P(o, c, s);
} return c; }; i.decode = function (e) { var r = new h(e); var n = r.length || r.byteLength; var t = 0; var o = 0; var a = null; var i = r[t++]; var c = i & y; var s = i >> 1 & E; if (_(s)) {
    var f = parseInt(r[t]);
    var l = 0;
    do {
        var f = parseInt(r[t]);
        o = o + (f & 127) * Math.pow(2, 7 * l);
        t++;
        l++;
    } while (f >= 128);
} if (w(s)) {
    if (c) {
        a = r[t++] << 8 | r[t++];
    }
    else {
        var u = r[t++];
        if (u) {
            a = new h(u);
            T(a, 0, r, t, u);
            a = p.strdecode(a);
        }
        else {
            a = "";
        }
        t += u;
    }
} var v = n - t; var d = new h(v); T(d, 0, r, t, v); return { id: o, type: s, compressRoute: c, route: a, body: d }; }; var T = function (e, r, n, t, o) { if ("function" === typeof n.copy) {
    n.copy(e, r, t, t + o);
}
else {
    for (var a = 0; a < o; a++) {
        e[r++] = n[t++];
    }
} }; var _ = function (e) { return e === i.TYPE_REQUEST || e === i.TYPE_RESPONSE; }; var w = function (e) { return e === i.TYPE_REQUEST || e === i.TYPE_NOTIFY || e === i.TYPE_PUSH; }; var v = function (e) { var r = 0; do {
    r += 1;
    e >>= 7;
} while (e > 0); return r; }; var d = function (e, r, n, t) { if (e !== i.TYPE_REQUEST && e !== i.TYPE_NOTIFY && e !== i.TYPE_RESPONSE && e !== i.TYPE_PUSH) {
    throw new Error("unkonw message type: " + e);
} n[t] = e << 1 | (r ? 1 : 0); return t + f; }; var b = function (e, r, n) { do {
    var t = e % 128;
    var o = Math.floor(e / 128);
    if (o !== 0) {
        t = t + 128;
    }
    r[n++] = t;
    e = o;
} while (e !== 0); return n; }; var g = function (e, r, n, t) { if (e) {
    if (r > o) {
        throw new Error("route number is overflow");
    }
    n[t++] = r >> 8 & 255;
    n[t++] = r & 255;
}
else {
    if (r) {
        n[t++] = r.length & 255;
        T(n, t, r, 0, r.length);
        t += r.length;
    }
    else {
        n[t++] = 0;
    }
} return t; }; var P = function (e, r, n) { T(r, n, e, 0, e.length); return n + e.length; }; if (typeof window != "undefined") {
    window.Protocol = p;
} })(typeof window == "undefined" ? module.exports : window.Protocol = {}, typeof window == "undefined" ? Buffer : Uint8Array, window);
(function () { function n(e) { if (e)
    return r(e); } function r(e) { for (var r in n.prototype) {
    e[r] = n.prototype[r];
} return e; } n.prototype.on = n.prototype.addEventListener = function (e, r) { this._callbacks = this._callbacks || {}; (this._callbacks[e] = this._callbacks[e] || []).push(r); return this; }; n.prototype.once = function (e, r) { var n = this; this._callbacks = this._callbacks || {}; function t() { n.off(e, t); r.apply(this, arguments); } t.fn = r; this.on(e, t); return this; }; n.prototype.off = n.prototype.removeListener = n.prototype.removeAllListeners = n.prototype.removeEventListener = function (e, r) { this._callbacks = this._callbacks || {}; if (0 == arguments.length) {
    this._callbacks = {};
    return this;
} var n = this._callbacks[e]; if (!n)
    return this; if (1 == arguments.length) {
    delete this._callbacks[e];
    return this;
} var t; for (var o = 0; o < n.length; o++) {
    t = n[o];
    if (t === r || t.fn === r) {
        n.splice(o, 1);
        break;
    }
} return this; }; n.prototype.emit = function (e) { this._callbacks = this._callbacks || {}; var r = [].slice.call(arguments, 1), n = this._callbacks[e]; if (n) {
    n = n.slice(0);
    for (var t = 0, o = n.length; t < o; ++t) {
        n[t].apply(this, r);
    }
} return this; }; n.prototype.listeners = function (e) { this._callbacks = this._callbacks || {}; return this._callbacks[e] || []; }; n.prototype.hasListeners = function (e) { return !!this.listeners(e).length; }; var e = "js-websocket"; var t = "0.0.1"; var s = window.Protocol; var i = null; var o = null; var f = s.Package; var c = s.Message; var a = n; var l = window.rsa; var u = 200; var v = 500; var d = 501; if (typeof Object.create !== "function") {
    Object.create = function (e) { function r() { } r.prototype = e; return new r; };
} var h = window; var p = Object.create(a.prototype); h.nano = p; var y = null; var E = 0; var T = {}; var _ = {}; var w = {}; var b = {}; var g = {}; var P = 0; var m = 0; var Y = 0; var k = 100; var A = null; var S = null; var N = null; var O = null; var H = null; var R = false; var K = null; var D = null; var U = 0; var C = 5e3; var I = 10; var J; var L = { sys: { type: e, version: t, rsa: {} }, user: {} }; var B = null; p.init = function (e, r) { B = r; var n = e.host; var t = e.port; var o = e.path; H = e.encode || j; O = e.decode || Q; var a = "ws://" + n; if (t) {
    a += ":" + t;
} if (o) {
    a += o;
} L.user = e.user; if (e.encrypt) {
    J = true;
    l.generate(1024, "10001");
    var i = { rsa_n: l.n.toString(16), rsa_e: l.e };
    L.sys.rsa = i;
} N = e.handshakeCallback; F(e, a, r); }; var Q = p.decode = function (e) { var r = c.decode(e); if (r.id > 0) {
    r.route = w[r.id];
    delete w[r.id];
    if (!r.route) {
        return;
    }
} r.body = ne(r); return r; }; var j = p.encode = function (e, r, n) { var t = e ? c.TYPE_REQUEST : c.TYPE_NOTIFY; if (i && i.lookup(r)) {
    var o = i.build(r);
    n = new o(n).encodeNB();
}
else {
    n = s.strencode(JSON.stringify(n));
} var a = 0; if (b && b[r]) {
    r = b[r];
    a = 1;
} return c.encode(e, t, a, r, n); }; var F = function (r, e, n) { console.log("connect to " + e); var r = r || {}; var t = r.maxReconnectAttempts || I; D = e; var o = function (e) { if (!!R) {
    p.emit("reconnect");
} M(); var r = f.encode(f.TYPE_HANDSHAKE, s.strencode(JSON.stringify(L))); q(r); }; var a = function (e) { $(f.decode(e.data), n); if (m) {
    Y = Date.now() + m;
} }; var i = function (e) { p.emit("io-error", e); console.error("socket error: ", e); }; var c = function (e) { p.emit("close", e); p.emit("disconnect", e); console.log("socket close: ", e); if (!!r.reconnect && U < t) {
    R = true;
    U++;
    K = setTimeout(function () { F(r, D, n); }, C);
    C *= 2;
} }; y = new WebSocket(e); y.binaryType = "arraybuffer"; y.onopen = o; y.onmessage = a; y.onerror = i; y.onclose = c; }; p.disconnect = function () { if (y) {
    if (y.disconnect)
        y.disconnect();
    if (y.close)
        y.close();
    console.log("disconnect");
    y = null;
} if (A) {
    clearTimeout(A);
    A = null;
} if (S) {
    clearTimeout(S);
    S = null;
} }; var M = function () { R = false; C = 1e3 * 5; U = 0; clearTimeout(K); }; p.request = function (e, r, n) { if (arguments.length === 2 && typeof r === "function") {
    n = r;
    r = {};
}
else {
    r = r || {};
} e = e || r.route; if (!e) {
    return;
} E++; x(E, e, r); T[E] = n; w[E] = e; }; p.notify = function (e, r) { r = r || {}; x(0, e, r); }; var x = function (e, r, n) { if (J) {
    n = JSON.stringify(n);
    var t = l.signString(n, "sha256");
    n = JSON.parse(n);
    n["__crypto__"] = t;
} if (H) {
    n = H(e, r, n);
} var o = f.encode(f.TYPE_DATA, n); q(o); }; var q = function (e) { y.send(e.buffer); }; var W = {}; var z = function (e) { if (!P) {
    return;
} var r = f.encode(f.TYPE_HEARTBEAT); if (S) {
    clearTimeout(S);
    S = null;
} if (A) {
    return;
} A = setTimeout(function () { A = null; q(r); Y = Date.now() + m; S = setTimeout(G, m); }, P); }; var G = function () { var e = Y - Date.now(); if (e > k) {
    S = setTimeout(G, e);
}
else {
    console.error("server heartbeat timeout");
    p.emit("heartbeat timeout");
    p.disconnect();
} }; var V = function (e) { e = JSON.parse(s.strdecode(e)); if (e.code === d) {
    p.emit("error", "client version not fullfill");
    return;
} if (e.code !== u) {
    p.emit("error", "handshake fail");
    return;
} te(e); var r = f.encode(f.TYPE_HANDSHAKE_ACK); q(r); if (B) {
    B(y);
} }; var X = function (e) { var r = e; if (O) {
    r = O(r);
} ee(p, r); }; var Z = function (e) { e = JSON.parse(s.strdecode(e)); p.emit("onKick", e); }; _[f.TYPE_HANDSHAKE] = V; _[f.TYPE_HEARTBEAT] = z; _[f.TYPE_DATA] = X; _[f.TYPE_KICK] = Z; var $ = function (e) { if (Array.isArray(e)) {
    for (var r = 0; r < e.length; r++) {
        var n = e[r];
        _[n.type](n.body);
    }
}
else {
    _[e.type](e.body);
} }; var ee = function (e, r) { if (!r.id) {
    e.emit(r.route, r.body);
    return;
} var n = T[r.id]; delete T[r.id]; if (typeof n !== "function") {
    return;
} n(r.body); }; var re = function (e, r) { for (var n = 0, t = r.length; n < t; n++) {
    ee(e, r[n]);
} }; var ne = function (e) { var r = e.route; if (e.compressRoute) {
    if (!g[r]) {
        return {};
    }
    r = e.route = g[r];
} if (o && o.lookup(r)) {
    return o.build(r).decode(e.body);
}
else {
    return JSON.parse(s.strdecode(e.body));
} return e; }; var te = function (e) { if (e.sys && e.sys.heartbeat) {
    P = e.sys.heartbeat * 1e3;
    m = P * 2;
}
else {
    P = 0;
    m = 0;
} oe(e); if (typeof N === "function") {
    N(e.user);
} }; var oe = function (e) { if (!e || !e.sys) {
    return;
} b = e.sys.dict; if (b) {
    b = b;
    g = {};
    for (var r in b) {
        g[b[r]] = r;
    }
} window.nano = p; }; })();
